<template>
  <div>
    <n-card style="margin-bottom: 5px;height: 100px;">
      <n-spin :show="resourceLoading">
        <n-form inline>
          <n-grid :x-gap="10">
            <n-grid-item span="6">
              <n-form-item label="资源选择" path="sdResourceId">
                <n-tooltip placement="bottom" trigger="hover" v-if="errorMessage.length > 0">
                  <template #trigger>
                    <n-button type="warning"> 异常 </n-button>
                  </template>
                  <span style="white-space: pre-wrap;"> {{ errorMessage }} </span>
                </n-tooltip>
                <n-select v-model:value="resourceInfo.resourceId" :options="resourceOption"
                          @update:value="resourceSelect"
                          style="margin-left: 5px;">
                </n-select>
                <n-button @click="refreshCache" style="margin-left:5px; ">
                  <template #icon>
                    <n-icon><SyncCircleOutline/></n-icon>
                  </template>
                </n-button>
              </n-form-item>
            </n-grid-item>
            <n-grid-item span="6">
              <n-form-item label="CHECKPOINT" path="defaultModel">
                <n-select
                    v-model:value="resourceInfo.model"
                    :options="modelOption"
                    @update:value="changeModel"
                    style="width: 100%"
                />
              </n-form-item>
            </n-grid-item>
            <n-grid-item :span="6">
              <n-form-item label="VAE" path="defaultVae">
                <n-select
                    :options="vaeOption"
                    v-model:value="resourceInfo.vae"
                    @update:value="changeVae"
                    clearable
                />
              </n-form-item>
            </n-grid-item>
            <n-grid-item span="6">
              <n-form-item :label="'CLIP终止层数{'+ resourceInfo.clipSkip+'}'" path="defaultVae">
                <n-slider v-model:value="resourceInfo.clipSkip" step="1" :min="1" :max="12"/>
              </n-form-item>
            </n-grid-item>
          </n-grid>
        </n-form>
      </n-spin>
    </n-card>
    <n-row>
      <n-col :span="14">
        <n-card>
          <n-space vertical>
            <n-tabs
                type='bar'
                animated
                placement="top"
                default-value="txt2Img"
                @update:value="handleUpdateValue"
            >
              <n-tab-pane name="txt2Img" tab="文生图" display-directive="show">
                <Txt2Img ref="txt2ImgRef" :defaultSdTxt2ImgPrompt="defaultConfig" :samperOptions="samperOptions" :schdulerOptions="schdulerOptions"></Txt2Img>
              </n-tab-pane>
              <n-tab-pane name="img2Img" tab="图生图" display-directive="show">
                <Img2img
                    v-if="resourceInfo.resourceId"
                    ref="img2ImgRef"
                    :defaultSdImg2ImgPrompt="defaultConfig"
                    :resourceId="resourceInfo.resourceId"
                    :samperOptions="samperOptions"
                ></Img2img>
              </n-tab-pane>
            </n-tabs>
          </n-space>
        </n-card>
      </n-col>
      <n-col :span="10">
        <n-card :style="{marginLeft: 5+'px'}">
          <n-tabs
              type='bar'
              animated
              placement="top"
          >
            <n-tab-pane name="生成" tab="生成" display-directive="show">
              <n-button
                  block
                  type="primary"
                  size="large"
                  :loading="buttonLoading"
                  style="margin-top: 20px"
                  @click="paint">
                生成
              </n-button>
              <n-el style="background: var(--hover-color);margin-top:10px">
                <n-space justify="center" style="padding: 10px;height: 400px">
                  <n-image
                      height="400"
                      :src="fileFunction.getViewFilePathByUserFileId(paintImagUrl)"
                  />
                </n-space>
              </n-el>
              <n-space style="margin-top:20px">
                <n-scrollbar x-scrollable style="max-height: 80px">
                  <div style="white-space: nowrap;">
                    <n-image
                        v-for="pic in picList"
                        preview-disabled
                        :lazy="true"
                        :width="70"
                        size="small"
                        @click="paintImagUrl = pic"
                        :class="{ 'selected': pic == paintImagUrl }"
                        style="margin-left: 10px;"
                        :src=fileFunction.getViewFilePathByUserFileId(pic)
                    />
                  </div>
                </n-scrollbar>
              </n-space>

              <n-button
                  block
                  type="info"
                  size="large"
                  :loading="reChosePicLoading"
                  @click="rechosePic"
                  style="margin-top: 20px"
                  v-if="props.defaultConfig">
                选取该图片
              </n-button>
            </n-tab-pane>
            <n-tab-pane name="Lora" tab="Lora模型" display-directive="show">
              <n-grid x-gap="12" :cols="4">
                <n-gi v-if="loraList.length >0" v-for="lora in loraList">
                  <n-card>
                    <template #cover>
                      <div class="image-container-lora" @contextmenu="handleContextMenu('lora', lora,$event)">
                        <n-image preview-disabled :src="fileFunction.getSDModelImage(lora.modelName,'Lora')" class="centered-image-lora"/>
                      </div>
                    </template>
                    <n-ellipsis style="width: 100%">
                      {{ lora.modelName }}
                    </n-ellipsis>
                  </n-card>
                </n-gi>
              </n-grid>
            </n-tab-pane>
            <n-tab-pane name="T.I Embedding" tab="T.I Embedding" display-directive="show">
              <n-grid x-gap="12" :cols="4">
                <n-gi v-if="embeddingList.length >0" v-for="embedding in embeddingList">
                  <n-card>
                    <template #cover>
                      <div class="image-container-lora"
                           @contextmenu="handleContextMenu('embedding' ,embedding, $event)">
                        <n-image :src="embedding.modelImage" class="centered-image-lora"/>
                      </div>
                    </template>
                    <n-ellipsis style="width: 100%">
                      {{ embedding.modelName }}
                    </n-ellipsis>
                  </n-card>
                </n-gi>
              </n-grid>
            </n-tab-pane>
            <!--              <n-tab-pane name="超网格" tab="超网格"></n-tab-pane>-->
          </n-tabs>
          <n-dropdown
              placement="bottom-start"
              trigger="manual"
              :x="x"
              :y="y"
              :options="options"
              :show="showDropdown"
              :on-clickoutside="clickOutSide"
              @select="handleSelect"
          />
        </n-card>
      </n-col>
    </n-row>
  </div>
</template>
<script lang="ts" setup>
import Txt2Img from '@/views/pages/aiart/stablediffusion/text2img.vue'
import Img2img from '@/views/pages/aiart/stablediffusion/img2Img.vue'
import {resourceController} from '@/api/resource/resourceController.api'
import {nextTick, onMounted, reactive, ref} from 'vue'
// @ts-ignore
import fileFunction from "@/libs/globalFunction/file"
import {sdControllerApi} from "@/api/sd/sdController.api"
import ControlNet from '@/components/paint/sd/controlNet.vue'
import RegionalPrompter from '@/components/paint/sd/regionalPrompter.vue'
import {storeToRefs} from "pinia";
import {useSystemStore} from "@/store/modules/useSystemStore"
import {storyController} from "@/api/story/story.api";
import { SyncCircleOutline} from '@vicons/ionicons5'

const txt2ImgRef = ref(null)
const img2ImgRef = ref(null)
const controlNetRef = ref(null)
const controlNetRef1 = ref(null)
const controlNetRef2 = ref(null)
const regionalPrompterRef = ref(null)
const modelOption = ref([])
const vaeOption = ref([])
const loraList = ref([])
const resourceOption = ref([])
const buttonLoading = ref(false)
const paintImagUrl = ref("")
const picList = ref([])
const embeddingList = ref([])
const showDropdown = ref(false)
const x = ref(0)
const y = ref(0)
const paintType = ref('txt2Img');
const selectModel = ref(null)
const reChosePicLoading = ref(false)
const samperOptions = ref([])
const errorMessage = ref('')
const schdulerOptions = ref([])

const {
  clientHeight,
  layoutHeaderHeight,
  collapsed,
  darkTheme,
} = storeToRefs(useSystemStore());


const options = [
  {
    label: '加入正向',
    key: 'addPositive'
  },
  {
    label: '加入反向',
    key: 'addNegative'
  }
]

const resourceInfo: SD.SDConfig = reactive({
  model: '',
  vae: '',
  clipSkip: 2,
  resourceId: ''
})

const resourceLoading = ref(false)
const resourceSelect = (value: string) => {
  resourceInfo.resourceId = value
  getResourceConfig(value)
}

const props = defineProps({
  resourceId: {
    type: String,
    default: ''
  },
  defaultConfig: {
    type: Object
  },
    from:{
        type:String,
        default:''
    },
    chosePic:{
      type:Function,
      default:()=>{}
    }
})

const defaultConfig = ref(props.defaultConfig);

onMounted(() => {
  getResourceInfo()
});

const rechosePic = () => {
    if(props.from === 'character'){
        props.chosePic(paintImagUrl.value)
    }

  if(defaultConfig.value.storyBoardId && defaultConfig.value.storyBoardId.length > 0) {
    reChosePicLoading.value = true
    const data = {
      id: defaultConfig.value.storyBoardId,
      imageUrl: paintImagUrl.value
    }
    storyController.updatePic(data).then(res => {
      if (res.code === 200) {
        window.$message.success('设置成功')
      }
    }).finally(() => {
      reChosePicLoading.value = false
    })
  }

}


const loadPrompt = (prompt: String, storyBoardId: string) => {
  defaultConfig.value.prompt = prompt
  defaultConfig.value.storyBoardId = storyBoardId
}

const loadImage = (fileId: string, type: string) => {
  if (type === 'img2img') {
    defaultConfig.value.img2imgFileId = fileId
  } else if (type === 'controlnet') {
    // defaultConfig.value.controlnetFileId = fileId
    // controlnet 加载图片
  }
}


defineExpose({
  loadPrompt, loadImage
})

/***
 * 获取绘画资源
 */
const getResourceInfo = () => {
  resourceController.getSDResource('SD').then(res => {
    if (res.code === 200) {
      // 判断当前SD是否在线
      res.data.forEach((item: any) => {
        // @ts-ignore
        resourceOption.value.push({
          label: item.resourceName,
          value: item.id
        })
      })
      if (res.data.length > 0) {
        resourceInfo.resourceId = res.data[0].id
        getResourceConfig(res.data[0].id)
      }
    } else {
      window.$message.error(res.msg);
    }
  })
}

const changeModel = (value: string) => {
  // resourceController.cha
  const data = {
    resourceId: resourceInfo.resourceId,
    key: 'sd_model_checkpoint',
    value: value
  }
  changeOption(data)
}

const changeVae = (value: string) => {
  const data = {
    resourceId: resourceInfo.resourceId,
    key: 'sd_vae',
    value: value
  }
  changeOption(data)
}

const changeOption = (data: any) => {
  resourceLoading.value = true
  resourceController.changeOption(data).then(res => {
    resourceLoading.value = false
    if (res.code === 200) {
      window.$message.success('切换成功!')
    } else {
      window.$message.error(res.msg);
    }
  })
}

const refreshCache = ()=>{
  resourceLoading.value = true
  sdControllerApi.refreshSDOption(resourceInfo.resourceId).then(res=>{
    resourceLoading.value = false
    if (res.code === 200) {
      window.$message.success('刷新成功!')
    } else {
      window.$message.error(res.msg);
    }
  }).finally(()=>{
    resourceLoading.value = false
  })
}



// 获取SD资源详情
const getResourceConfig = (resouceId: string) => {
  resourceLoading.value = true
  resourceController.getReousceConfig(resouceId).then(res => {
    resourceLoading.value = false
    if (res.code === 200) {
      const stableDiffusionInfo = res.data
      errorMessage.value = stableDiffusionInfo.message
      if (!stableDiffusionInfo.online){
        window.$message.error(stableDiffusionInfo.message)
        return
      }
      modelOption.value = []
      vaeOption.value = []
      loraList.value = []
      resourceInfo.model = res.data.selectModel
      resourceInfo.vae = res.data.selectVae
      stableDiffusionInfo.modelList.forEach((item: any) => {
        // @ts-ignore
        modelOption.value.push({
          label: item.fileName,
          value: item.fileName,
          url: item.modelImage
        })
      })
      stableDiffusionInfo.vaeList.forEach((item: any) => {
        // @ts-ignore
        vaeOption.value.push({
          label: item,
          value: item
        })
      })

      stableDiffusionInfo.samplerList.forEach((item: any) => {
        // @ts-ignore
        samperOptions.value.push({
          label: item,
          value: item
        })
      })


      res.data.schedulerList.forEach((item: any) => {
        // @ts-ignore
        schdulerOptions.value.push({
          label: item.label,
          value: item.name
        })
      })

      loraList.value = stableDiffusionInfo.loraList
      embeddingList.value = stableDiffusionInfo.embeddingList
    }
  }).finally(() => {
    resourceLoading.value = false
  })
}

const getControlNetScript = () => {
  let controlNetScript = null
  const controlNetInfos = []
  if (controlNetRef.value) {
    const controlNetInfo = controlNetRef?.value.getControlNetInfo()
    if (controlNetInfo.is_enable) {
      controlNetInfos.push(controlNetInfo)
    }
  }
  if (controlNetRef1.value) {
    const controlNetInfo1 = controlNetRef1?.value.getControlNetInfo()
    if (controlNetInfo1.is_enable) {
      controlNetInfos.push(controlNetInfo1)
    }
  }
  if (controlNetRef2.value) {
    const controlNetInfo2 = controlNetRef2?.value.getControlNetInfo()
    if (controlNetInfo2.is_enable) {
      controlNetInfos.push(controlNetInfo2)
    }
  }

  if (controlNetInfos.length > 0) {
    controlNetScript = {}
    controlNetScript['args'] = controlNetInfos
  }
  return controlNetScript
}

const getRegionalPrompterScript = () =>{
  let regionalPrompterScript = null
  if( regionalPrompterRef.value ){
    const regionPrompterInfo = regionalPrompterRef?.value.getScriptInfo()
    if(regionPrompterInfo[0]){
      regionalPrompterScript = {}
      regionalPrompterScript['args'] = regionPrompterInfo
    }
  }
  return regionalPrompterScript
}

const getAlwaysonScript = () => {
  let alwaysonScript = null
  const controNetScript = getControlNetScript()
  if (controNetScript) {
    alwaysonScript = {}
    alwaysonScript['ControlNet'] = controNetScript
  }
  const regionalPrompterScript = getRegionalPrompterScript()
  console.log("regionalPrompterScript",regionalPrompterScript)
  if(regionalPrompterScript){
    if(alwaysonScript){
      alwaysonScript['Regional Prompter'] = regionalPrompterScript
    }else{
      alwaysonScript = {}
      alwaysonScript['Regional Prompter'] = regionalPrompterScript
    }
  }
  return alwaysonScript
}

const paint = async () => {
  buttonLoading.value = true
  // 获取controlNet信息
  const alwaysonScript = getAlwaysonScript()
  if (paintType.value == 'txt2Img') {
    const param = txt2ImgRef.value.getTxt2ImgPrompt()
    param.alwaysonScript = alwaysonScript
    param.sdResourceId = resourceInfo.resourceId
    if (alwaysonScript) {
      param.alwaysonScript = alwaysonScript
    }
    try {
      const data = await sdControllerApi.generateText2ImgAndCheck(param, 1000 * 120)
      addPaintLog(data.id)
      const images = data.userFileId.split(',')
      for (let i = 0; i < images.length; i++) {
        picList.value.push(images[i])
      }
      paintImagUrl.value = images[0];
    } catch (e) {
      console.log(e)
      window.$message.error("出错啦！")
    } finally {
      buttonLoading.value = false
    }
  } else {
    const param = await img2ImgRef.value.getImg2ImgPrompt()
    param.sdResourceId = resourceInfo.resourceId
    try {
      const data = await sdControllerApi.generateImg2ImgAndCheck(param, 1000 * 120)
      addPaintLog(data.id)
      const images = data.userFileId.split(',')
      for (let i = 0; i < images.length; i++) {
        picList.value.push(images[i])
      }
      paintImagUrl.value = images[0];
    } catch (e) {
      window.$message.error("出错啦！")
    } finally {
      buttonLoading.value = false
    }
  }
}


const addPaintLog = (taskId: string) => {
  if (defaultConfig.value?.storyBoardId && defaultConfig.value.storyBoardId.length > 0) {
    sdControllerApi.addStoryBoarPaintLog(defaultConfig.value.storyBoardId, taskId).then(res => {
      if (res.code != 200) {
        window.$message.error(res.msg)
      }
    })
  }
}


const handleContextMenu = (type: string, model: any, e: MouseEvent) => {
  e.preventDefault()
  selectModel.value = Object.assign({}, model);
  showDropdown.value = false
  if (type === 'lora') {
    selectModel.value.modelName = '<lora:' + model.modelName + ':1>'
  }
  nextTick().then(() => {
    showDropdown.value = true
    x.value = e.clientX
    y.value = e.clientY
  })
}

const clickOutSide = () => {
  showDropdown.value = false
}

const handleSelect = (key: string | number) => {
  showDropdown.value = false
  if (paintType.value == 'txt2Img') {
    if (key === 'addPositive') {
      txt2ImgRef.value.addPrompt(selectModel.value.modelName, 1)
    } else if (key === 'addNegative') {
      txt2ImgRef.value.addPrompt(selectModel.value.modelName, -1)
    }
  } else {
    if (key === 'addPositive') {
      img2ImgRef.value.addPrompt(selectModel.value.modelName, 1)
    } else if (key === 'addNegative') {
      img2ImgRef.value.addPrompt(selectModel.value.modelName, -1)
    }
  }

}

const handleUpdateValue = (e: string) => {
  paintType.value = e
};


</script>

<style>

.image-container-lora {
  height: 150px; /* 设置容器的固定高度 */
  display: flex; /* 使用Flex布局 */
  align-items: center; /* 垂直居中 */
  justify-content: center; /* 水平居中 */
}

.centered-image-lora {
  max-height: 100%; /* 图片的最大高度为容器高度，宽度会自动适应宽高比例 */
  max-width: 100%; /* 图片的最大宽度为容器宽度，高度会自动适应宽高比例 */
}

.selected {
  border: 3px solid #8250df;
}


</style>
